import tnx from '@/tnx.js';
import truenewxProject from './truenewx-project.js';
import ModuleLayer from '../enums/ModuleLayer.js';

export const BASIC_PROJECT_PROPERTY_KEY = 'project.basic';

export default {
    parseProject(path, xml, onParsed) {
        let result = tnx.util.xml.parse(xml);
        let project = result.project;
        if (project) {
            project.path = path;
            project.packaging = project.packaging || 'jar';
            project.groupId = project.groupId || project.parent?.groupId;
            project.artifactId = project.artifactId || project.parent?.artifactId;
            project.version = project.version || project.parent?.version;
            if (project.dependencies) {
                project.dependencies = project.dependencies.dependency;
                if (!Array.isArray(project.dependencies)) {
                    project.dependencies = [project.dependencies];
                }
            }
            if (project.modules) {
                let modules = project.modules.module;
                if (!Array.isArray(modules)) {
                    modules = [modules];
                }
                modules.sort();
                project.modules = [];
                if (modules.length) {
                    let dir = tnx.util.file.getParentDir(path);
                    this._loadModule(dir, modules, (moduleProject, index) => {
                        project.modules.push(moduleProject);
                        if (index === modules.length - 1) {
                            if (typeof onParsed === 'function') {
                                onParsed(project);
                            }
                        }
                    });
                    // 指定了回调函数，则等待解析完成再调用，否则直接返回工程对象结果
                    return typeof onParsed === 'function' ? undefined : project;
                }
            } else { // 确保有modules属性
                project.modules = [];
            }
            // 指定了回调函数，则调用回调函数，否则直接返回工程对象结果
            if (typeof onParsed === 'function') {
                onParsed(project);
            } else {
                return project;
            }
        }
        return undefined;
    },
    _loadModule(dir, modules, callback, index = 0) {
        if (modules?.length && index < modules.length) {
            let module = modules[index];
            let modulePomPath = tnx.util.file.joinPath(dir, module, 'pom.xml');
            tnx.util.file.read(modulePomPath).then(modulePomXml => {
                this.parseProject(modulePomPath, modulePomXml, moduleProject => {
                    callback(moduleProject, index);
                    this._loadModule(dir, modules, callback, index + 1);
                });
            }).catch(error => {
                let exists = true;
                if (Array.isArray(error)) {
                    exists = error[1];
                    error = error[0];
                }
                if (exists) {
                    tnx.error('声明了模块 ' + module + '，但找不到文件 ' + modulePomPath);
                } else {
                    tnx.error(error.message ?? error);
                }
            });
        }
    },
    loadProject(path, completed) {
        return new Promise((resolve, reject) => {
            tnx.util.file.read(path).then(xml => {
                if (completed) {
                    this.parseProject(path, xml, project => {
                        project.singleArch = this.isSingleArch(project);
                        resolve(project);
                    });
                } else {
                    let project = this.parseProject(path, xml);
                    project.singleArch = this.isSingleArch(project);
                    resolve(project);
                }
            }).catch(reject);
        });
    },
    isSingleArch(project) {
        if (project && project.parent && project.parent.groupId === truenewxProject.groupId) {
            if (project.parent.artifactId === 'tnxjee') {
                return true;
            }
            if (project.parent.artifactId === 'tnxjeex') {
                return false;
            }
        }
        // 未决
        return undefined;
    },
    getVersion(project) {
        let version = {};
        if (project.parent && project.parent.groupId === truenewxProject.groupId
            && truenewxProject.modules.includes(project.parent.artifactId)) {
            version.truenewx = project.parent.version;
        }
        if (!version.truenewx) {
            version.truenewx = truenewxProject.getDefaultVersion();
        }
        let properties = project.properties;
        if (properties) {
            version.jdk = properties['project.java.version'] || properties['maven.compiler.source'];
        }
        if (!version.jdk) {
            version.jdk = truenewxProject.getJdkVersion(version.truenewx);
        }
        return version;
    },
    _resolveDatabaseVendor(resourceDir) {
        let configFilenames = ['bootstrap.yaml', 'bootstrap.yml', 'bootstrap.properties',
            'application.yaml', 'application.yml', 'application.properties'];
        const resolveDatabase = function (resourceDir) {
            return new Promise((resolve, reject) => {
                if (configFilenames.length) {
                    let filename = configFilenames.pop();
                    let filePath = tnx.util.file.joinPath(resourceDir, filename);
                    tnx.util.file.exists(filePath).then(exists => {
                        if (exists) {
                            tnx.util.file.read(filePath).then(fileContent => {
                                if (filename.endsWith('.properties')) {
                                    let lines = fileContent.split('\n');
                                    for (let line of lines) {
                                        if (line.startsWith('spring.jpa.database=')) {
                                            let database = line.substring('spring.jpa.database='.length);
                                            if (database) {
                                                resolve(database);
                                            } else {
                                                resolveDatabase(resourceDir).then(resolve).catch(reject);
                                            }
                                            return;
                                        }
                                    }
                                    resolveDatabase(resourceDir).then(resolve).catch(reject);
                                } else {
                                    let yaml = new tnx.Yaml(fileContent);
                                    let database = yaml.get(['spring', 'jpa', 'database']);
                                    if (database) {
                                        resolve(database);
                                    } else {
                                        resolveDatabase(resourceDir).then(resolve).catch(reject);
                                    }
                                }
                            });
                        } else {
                            resolveDatabase(resourceDir).then(resolve).catch(reject);
                        }
                    });
                } else {
                    reject();
                }
            });
        }
        return resolveDatabase(resourceDir);
    },
    readDatabaseVendor(project) {
        return new Promise((resolve, reject) => {
            let projectDir = tnx.util.file.getParentDir(project.path);
            for (let module of project.modules) {
                if (module.artifactId.endsWith('-repo')) {
                    let resourceDir = tnx.util.file.joinPath(projectDir, module.artifactId, 'src', 'main', 'resources');
                    this._resolveDatabaseVendor(resourceDir).then(resolve).catch(() => {
                        // 在repo工程下找不到，则尝试在可能依赖的公共repo工程中找
                        let repoPomPath = tnx.util.file.joinPath(projectDir, module.artifactId, 'pom.xml');
                        this.loadProject(repoPomPath).then(repoMavenProject => {
                            let dependencies = repoMavenProject.dependencies.dependency;
                            if (dependencies) {
                                if (!Array.isArray(dependencies)) {
                                    dependencies = [dependencies];
                                }
                                for (let dependency of dependencies) {
                                    let artifactId = dependency.artifactId;
                                    if (artifactId.endsWith('-repo') && artifactId !== 'tnxjee-repo') {
                                        let dependencyResourceDir = tnx.util.file.joinPath(
                                            tnx.util.file.getParentDir(projectDir),
                                            artifactId.substring(0, artifactId.length - '-repo'.length),
                                            artifactId, 'src', 'main', 'resources');
                                        this._resolveDatabaseVendor(dependencyResourceDir).then(resolve);
                                        return;
                                    }
                                }
                            }
                            // 找不到数据库配置
                            resolve();
                        }).catch(reject);
                    });
                    return;
                }
            }
            reject('对应的Maven工程下没有repo层');
        });
    },
    readDependencyModelModuleDir(project) {
        return new Promise((resolve, reject) => {
            let projectDir = tnx.util.file.getParentDir(project.path);
            for (let module of project.modules) {
                if (module.artifactId.endsWith('-model')) {
                    let modelPomPath = tnx.util.file.joinPath(projectDir, module.artifactId, 'pom.xml');
                    this.loadProject(modelPomPath).then(modelMavenProject => {
                        let dependencies = modelMavenProject.dependencies.dependency;
                        if (dependencies) {
                            if (!Array.isArray(dependencies)) {
                                dependencies = [dependencies];
                            }
                            for (let dependency of dependencies) {
                                let artifactId = dependency.artifactId;
                                if (artifactId.endsWith('-model') && artifactId !== 'tnxjee-model') {
                                    let dependencyModuleDir = tnx.util.file.joinPath(
                                        tnx.util.file.getParentDir(projectDir),
                                        artifactId.substring(0, artifactId.length - '-model'.length), artifactId);
                                    resolve(dependencyModuleDir);
                                    return;
                                }
                            }
                        }
                        resolve();
                    }).catch(reject);
                    return;
                }
            }
            resolve();
        });
    },
    getDefaultGroupId(parent) {
        if (parent.groupId && parent.artifactId) {
            let groupArray = parent.groupId.split('.');
            let artifactArray = parent.artifactId.split('-');
            for (let i = 0; i < artifactArray.length; i++) {
                if (groupArray.contains(artifactArray[i])) {
                    artifactArray.splice(i, 1);
                    i--;
                } else {
                    break;
                }
            }
            return groupArray.join('.') + '.' + artifactArray.join('.');
        }
        return undefined;
    },
    getLayerKey(artifactId) {
        let index = artifactId.lastIndexOf('-');
        if (index >= 0) {
            let layerName = artifactId.substring(index + 1);
            if (ModuleLayer.valueOf(layerName.toUpperCase())) {
                return layerName;
            }
        }
        return artifactId;
    },
    containsLayer(modules, layer) {
        if (modules) {
            for (let module of modules) {
                let moduleLayer = this.getLayerKey(module.artifactId);
                if (moduleLayer.toLowerCase() === layer.toLowerCase()) {
                    return true;
                }
            }
        }
        return false;
    },
    getRepoTypes(dependencies) {
        let repoTypes = [];
        if (dependencies) {
            for (let dependency of dependencies) {
                if (dependency.groupId === 'org.truenewx.tnxjee'
                    && dependency.artifactId.startsWith('tnxjee-repo-')) {
                    let repoType = dependency.artifactId.substring('tnxjee-repo-'.length).toUpperCase();
                    repoTypes.push(repoType);
                }
            }
        }
        return repoTypes;
    },
    getSsrEnabled(rootProject, module) {
        if (module.dependencies) {
            let suffix = module.artifactId.substring(module.artifactId.lastIndexOf('-'));
            for (let dependency of module.dependencies) {
                if (dependency.groupId === 'org.truenewx.tnxjee'
                    && dependency.artifactId === 'tnxjee-webmvc-view') {
                    return 'direct'; // 直接启用
                }
                // 如果依赖的是其它模块，则看依赖的模块是否启用了SSR
                if (rootProject) {
                    let dependencyModule = this.findModule(rootProject, dependency);
                    if (dependencyModule && dependency.artifactId.endsWith(suffix)) {
                        if (this.getSsrEnabled(rootProject, dependencyModule)) {
                            return 'indirect'; // 间接启用
                        }
                    }
                }
            }
        }
        return null;
    },
    getNacosEnabled(rootProject, module) {
        if (module.dependencies) {
            let suffix = module.artifactId.substring(module.artifactId.lastIndexOf('-'));
            for (let dependency of module.dependencies) {
                if (dependency.groupId === 'com.alibaba.cloud'
                    && dependency.artifactId === 'spring-cloud-starter-alibaba-nacos-config') {
                    return 'direct'; // 直接启用
                }
                // 如果依赖的是其它模块，则看依赖的模块是否启用了Nacos
                if (rootProject) {
                    let dependencyModule = this.findModule(rootProject, dependency);
                    if (dependencyModule && dependency.artifactId.endsWith(suffix)) {
                        if (this.getNacosEnabled(rootProject, dependencyModule)) {
                            return 'indirect'; // 间接启用
                        }
                    }
                }
            }
        }
        return null;
    },
    findModule(project, module) {
        if (project && project.modules?.length && module) {
            for (let projectModule of project.modules) {
                if (projectModule.groupId === module.groupId && projectModule.artifactId === module.artifactId) {
                    return projectModule;
                }
                let subModule = this.findModule(projectModule, module);
                if (subModule) {
                    return subModule;
                }
            }
        }
        return null;
    },
    dependsOtherModuleLayer(rootProject, module) {
        // 依赖为工程中包含的模块且以相同-层级结尾，则认为依赖了其它模块的相同层级
        let suffix = module.artifactId.substring(module.artifactId.lastIndexOf('-'));
        return suffix && module.dependencies.some(dependency =>
            this.findModule(rootProject, dependency) && dependency.artifactId.endsWith(suffix));
    },
    BASIC_PROJECT_PROPERTY_KEY,
    isBasic(module) {
        let properties = module.properties;
        return properties && properties[BASIC_PROJECT_PROPERTY_KEY] === 'true';
    },
}
